using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ZPod.MTG.Windows
{
	public partial class PlayerView : UserControl
	{
		#region Menu Titles
		const string MenuAssociate = "&Asociar a carta";
		const string MenuTap = "&Girar";
		const string MenuUntap = "&Enderezar";
		const string MenuGraveyard = "Al &cementerio";
		const string MenuPlayMana = "Bajar &Mana";
		const string MenuPlayCreature = "Bajar &Criatura";
		const string MenuPlayGeneral = "Bajar &Otro";
		const string MenuBackToDeckTop = "&Devolver al mazo (arriba)";
		const string MenuBackToDeckBottom = "&Devolver al mazo (abajo)";

		const string MenuBackToHand = "&Devolver a la mano";

		const string MenuViewDeck = "&Ver Mazo";
		const string MenuShuffleDeck = "&Mezclar";

		const string MenuAddToken = "Agregar &Token";

		const string MenuGenerateCache = "Pre-generar cache";
		#endregion

		#region Properties
		
		Card _graveyard = new Card("Graveyard");
		Deck _deck;
		bool _canControl = true;

		#endregion

		#region Public Properties

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		[Browsable(false)]
		public PlayerState State
		{
			get
			{
				PlayerState state = new PlayerState()
				{
					Date = DateTime.Now,
					Creatures = panelCreatures.CardsWithState,
					General = panelGeneral.CardsWithState,
					Graveyard = _graveyard.AttachedCards,
					Mana = panelMana.CardsWithState,
					Hand = panelHand.Cards,
					Deck = _deck
				};

				return state;
			}

			set
			{
				panelCreatures.Clear();
				panelCreatures.AddCards(value.Creatures, true);

				panelGeneral.Clear();
				panelGeneral.AddCards(value.General, true);

				panelMana.Clear();
				panelMana.AddCards(value.Mana, true);

				_graveyard.DetachAll();
				_graveyard.AttachRange(value.Graveyard);

				panelHand.Clear();
				panelHand.AddCards(value.Hand);

				Deck = value.Deck;
			}
		}

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		[Browsable(false)]
		public Deck Deck
		{
			get
			{
				return _deck;
			}

			set
			{
				if (value != null)
				{
					_deck = value;
				}
				else
				{
					_deck = new Deck();
				}

				txtDeckCount.Text = _deck.Count.ToString();
			}
		}

		public bool CanControl
		{
			get
			{
				return _canControl;
			}

			set
			{
				_canControl = value;
				panelHand.CanControl = value;
				buttonUntap.Enabled = value;
				InitializePanels();
			}
		}
	
		#endregion

		#region Public Events

		public event EventHandler StateChanged;

		#endregion

		#region Public Constructors

		public PlayerView()
		{
			InitializeComponent();

			InitializePanels();
		}

		#endregion

		#region Private Methods

		#region Support Methods

		private void InitializePanels()
		{
			#region Menu para paneles
			SetPanelMenues(panelCreatures);
			SetPanelMenues(panelGeneral);
			SetPanelMenues(panelHand);
			SetPanelMenues(panelMana);
			#endregion

			AddTokenMenu();

			SetDeckActions();

			panelHand.CanControl = CanControl;
			buttonUntap.Enabled = CanControl;
		}

		private void AddTokenMenu()
		{
			panelCreatures.ContextMenu = new ContextMenu();
			if (CanControl)
			{
				panelCreatures.ContextMenu.MenuItems.Add(MenuAddToken, AddTokenHandler);
			}
		}

		void SetDeckActions()
		{
			pictureDeck.ContextMenu = new ContextMenu();
			pictureDeck.DoubleClick -= new EventHandler(pictureDeck_DoubleClick);

			if (CanControl)
			{
				//Sacar una carta del mazo
				pictureDeck.DoubleClick += new EventHandler(pictureDeck_DoubleClick);

				pictureDeck.ContextMenu.MenuItems.Add(MenuShuffleDeck, (o, e) => Deck.Shuffle());
				pictureDeck.ContextMenu.MenuItems.Add(MenuViewDeck, ShowDeckEventHandler);

			}

			pictureDeck.ContextMenu.MenuItems.Add(MenuGenerateCache, GenerateCacheEventHandler);
		}

		void SetPanelMenues(CardPanel panel)
		{
			panel.ContextualOptions.Clear();
			panel.ClearCardDetailContextualOptions();

			if (CanControl)
			{
				panel.ContextualOptions.Add(MenuTap, Tap);
				panel.ContextualOptions.Add(MenuUntap, Untap);
				panel.ContextualOptions.Add(MenuPlayMana, SendToMana);
				panel.ContextualOptions.Add(MenuPlayCreature, SendToCreatures);
				panel.ContextualOptions.Add(MenuPlayGeneral, SendToGeneral);
				panel.ContextualOptions.Add(MenuBackToHand, SendToHand);
				panel.ContextualOptions.Add(MenuAssociate, Associate);
				panel.ContextualOptions.Add(MenuGraveyard, SendToGraveyard);
				panel.ContextualOptions.Add(MenuBackToDeckTop, SendToDeckTop);
				panel.ContextualOptions.Add(MenuBackToDeckBottom, SendToDeckBottom);

				panel.AddCardDetailContextualOption(MenuBackToHand, AttachedCardToHand);
			}
		}

		void MoveBetweenPanels(int cardIndex, CardPanel from, CardPanel to)
		{
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				Card card = from.Cards[cardIndex];
				from.RemoveCard(cardIndex);
				to.AddCard(card);
			}
			SendStateChanged();
		}
		
		void SendStateChanged()
		{
			if (StateChanged != null)
			{
				StateChanged(this, EventArgs.Empty);
			}
		}

		#endregion

		#region Event Handlers

		#region Panels and Cards Handlers
		void AddTokenHandler(object sender, EventArgs e)
		{
			string nombre = InputBox.ShowInputBox("Nuevo Token");
			if (!String.IsNullOrEmpty(nombre))
			{
				using (var freezer = new FormFreezer(this.FindForm(), true))
				{
					Card token = new Card("Token: " + nombre);
					panelCreatures.AddCard(token);

					SendStateChanged();
				}
			}
		}

		void GenerateCacheEventHandler(Object sender, EventArgs e)
		{
			using (var cacheDialog = new CacheLoaderDialog(_deck.Cards))
			{
				cacheDialog.ShowDialog();
			}
		}

		void ShowDeckEventHandler(Object sender, EventArgs e)
		{
			using (CardList dialog = new CardList(Deck.ToList()))
			{
				dialog.Text = "Sacar una carta";
				if (dialog.ShowDialog() == DialogResult.OK && dialog.SelectedIndex >= 0)
				{
					using (var freezer = new FormFreezer(this.FindForm(), true))
					{
						Card selectedCard = Deck.Take(dialog.SelectedIndex);
						txtDeckCount.Text = Deck.Count.ToString();

						panelHand.AddCard(selectedCard);

						SendStateChanged();
					}
				}
			}
		}

		void AttachedCardToHand(Card selectedCard, int index, CardPanel panel)
		{
			Card attachedCard = panel[index];
			selectedCard.Detach(index);

			MoveBetweenPanels(index, panel, panelHand);
		}

		void Associate(int cardIndex, CardPanel panel)
		{
			using (var dialog = new CardList(panelGeneral.Cards))
			{
				if (dialog.ShowDialog() == DialogResult.OK && dialog.SelectedCard != null)
				{
					Card selectedCard = dialog.SelectedCard;
					if (selectedCard != panel.Cards[cardIndex])
					{
						selectedCard.Attach(panel.Cards[cardIndex]);

						panel.RemoveCard(cardIndex);

						SendStateChanged();
					}
				}
			}
		}

		void Tap(int cardIndex, CardPanel panel)
		{
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				panel.RotateCard(cardIndex);
			}
			SendStateChanged();
		}

		void Untap(int cardIndex, CardPanel panel)
		{
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				panel.StraightCard(cardIndex);
			}

			SendStateChanged();
		}

		void SendToGraveyard(int cardIndex, CardPanel panel)
		{
			Card card = panel.Cards[cardIndex];
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				panel.RemoveCard(cardIndex);
			}

			_graveyard.Attach(card);
			SendStateChanged();
		}

		void SendToDeckTop(int cardIndex, CardPanel panel)
		{
			Card card = panel.Cards[cardIndex];
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				panel.RemoveCard(cardIndex);
			}

			_deck.PutOnTop(card);

			SendStateChanged();
		}

		void SendToDeckBottom(int cardIndex, CardPanel panel)
		{
			Card card = panel.Cards[cardIndex];
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				panel.RemoveCard(cardIndex);
			}

			_deck.PutOnBack(card);

			SendStateChanged();
		}

		void SendToMana(int cardIndex, CardPanel panel)
		{
			MoveBetweenPanels(cardIndex, panel, panelMana);
		}

		void SendToCreatures(int cardIndex, CardPanel panel)
		{
			MoveBetweenPanels(cardIndex, panel, panelCreatures);
		}

		void SendToGeneral(int cardIndex, CardPanel panel)
		{
			MoveBetweenPanels(cardIndex, panel, panelGeneral);
		}

		void SendToHand(int cardIndex, CardPanel panel)
		{
			MoveBetweenPanels(cardIndex, panel, panelHand);
		}

		void GraveyardToHand(int cardIndex, CardPanel panel)
		{
			_graveyard.Detach(cardIndex);
			MoveBetweenPanels(cardIndex, panel, panelHand);
		}

		#endregion

		#region Click Event Handlers

		void buttonGraveyard_Click(object sender, EventArgs e)
		{
			using (CardDetailDialog dialog = new CardDetailDialog(_graveyard))
			{
				if (CanControl)
				{
					dialog.AddContextualOption(MenuBackToHand, GraveyardToHand);
					dialog.RefreshCards();
				}
				dialog.ShowDialog();
			}
		}

		void pictureDeck_DoubleClick(object sender, EventArgs e)
		{
			if (CanControl)
			{
				if (Deck.Count > 0)
				{
					using (var freezer = new FormFreezer(this.FindForm(), true))
					{
						Card newCard = Deck.Take();

						panelHand.AddCard(newCard);

						txtDeckCount.Text = Deck.Count.ToString();
					}

					SendStateChanged();
				}
			}
		}

		void buttonUntap_Click(object sender, EventArgs e)
		{
			using (var freezer = new FormFreezer(this.FindForm(), true))
			{
				panelGeneral.StraightAll();
				panelCreatures.StraightAll();
				panelMana.StraightAll();
			}
		}

		#endregion

		#endregion

		#endregion
	}
}
